\section{设计方案}
\subsection{总体设计思路}
\textcolor{black}{在设计的顶层模块 soc\_list\_top 中包含 my\_cpu（cpu 模块）、inst\_ram（指令存储器）、数据存储器。指令存储器是直接将指令输入进 cpu，而数据存储器是将数据利用统一的接口输入 cpu。由 data\_ram 模块提供数据。具体的结构图如下：}
\subsection{mips模块设计}
\begin{itemize}
    \item cpu 的主要设计思路就是，通过内置的 pc 指令计数器，从指令寄存器中读出指32 位的指
    令数据，再根据指令需要从数据模块得到数据。根据指令的翻译结果对数据、程序运行过程进行相
    应的操作，以达到控制程序、实现程序的目的。Cpu 的实现主要分为 datapath 和 controller 
    两个部分，contro ller 部分负责对指令进行翻译，将对应的控制信息号提供给 datapath，datapath 
    数据通路部分是操作部分——寄存器的读写、运算、访存等。上述两个部分基于五级流水线实现，分
    别分为了 IF（取址）、ID（译码）、EXE（执行）、MEM（）访存、WB（写回），针对 52条指令
    的特性实现了数据前推、数据冒险、流水线暂停等功能
    \item Controller 模块内部由 main\_decoder（控制信号译码模块）和 aludec（运算信号译
    码模块）。main\_decoder 负责对指令进行译码，输出全局的 cpu 控制信号。
    \item main\_decoder 主要是根据指令的高六位（op 字段）、低六位（funct 字段）进行指
    令的解码译码操作，将对应指令的对应控制信号（分支、访存使能、寄存器读写、寄存器号等）
    通过匹配进行赋值，然后流入 datapath 中。
    \item aludec 主要对不同指令产生的运算控制信号，进行不同的运算操作。同样是根据op 字段
    和 funct 字段生成对应的 alu 运算控制信号，不同的指令有不同的运算方式和操作数。
    Controller 模块在 ID 阶段输出所有的信号，在 datapath 中不同的阶段取到不同的控制信号，
    信号依次流水到 EXE、MEM、WB 阶段。
    \item datapath 模块的主要思路是将整个 cpu 的单元连接起来。其中包括：adder(加法器)、
    pc(pc 寄存器)、flopenrc(有使能有复位有清空的寄存器)、flopenr(有使能有复位的寄存器)、
    floprc( 有复位的有清空的寄存器)、sl2(左移两位)、regfile(寄存器堆)、mux2(二选一多路选择器)、
    branchcmp(相等比较器)、signext(立即数拼接)、mux3(三选一多路选择器)、mux4(四选一多路选择器)、
    div(除法器)、alu(运算器)、selectdata(数据选择器)、hazard(控制冒险单元)。接下来对每个模块进
    行大致的阐述。
    \item adder 单元主要是对 pc 进行加法运算，因为 pc 在 IF 更新的需要，所以单独使用一个加法器
    对 pc 进行运算，一般对 pc 操作时是 pc+4，但是当遇到 al 类型的分支指令或者跳转指令时就是 pc+8。
    之后得到 pc 还会根据跳转和分支的控制信号求出下一条指令的真正 pc。
    \item pc 单元是 pc 寄存器，存储了当前 pc 的值，在暂停的时候保存当前的 pc，在正常流水的时候
    就将下一条 pc 的值存入，保证 pc 的正常取值。
    \item flopenrc、flopenr、floprc 单元是具有不同功能的 D 触发器单元，将信号流水至不同的阶段。
    \item sl2 单元将输入的数据左移两位，末位用 0 补足，是在跳转指令时计算跳转地址的中间处理过程
    \item regfile 单元是 32 个 32 位的通用寄存器堆。
    \item mux2、mux3、mux4 单元是多路选择器，在数据通路中用于堆不同数据的选择，比如数据前推和运算操作数选择等。
    \item Div 单元是除法器，由于除法需要进行多个周期进行运算，利用一个单独的模块进行除法，在执行
    到除法指令时将流水线暂停等待除法器运算完成。同时乘法和除法的输入时两个 32 位的操作数，但输出
    是 64 位的结果，这里利用 holi 寄存器存储乘除法结果。
    \item alu 单元主要负责对相应的数据进行基本运算，根据 controller 输出的 aludec 控制信号，对不
    同的指令和不同的操作数进行运算，得到运算结果流入 datapath。
    \item selectData 单元将从数据存储模块得到的数据根据指令的需求进行处理，得到部分字段。
    \item hazard 单元通过对寄存器号的比较，读写信号的判断，处理数据冒险。利用数据前推，对相应冒险
    的数据进行选择，在 ID、EXE 阶段提前得到数据。
\end{itemize}

\subsection{datapath模块设计}
\begin{itemize}
    \item Datapath 模块的结构示意图如下：
    \item 模块输入输出如下：
    \item 在 IF 取指阶段。主要的工作就是对 pc 进行更新和判断。先对 pc 进行加 4，得到pcplus4F，
    流入 ID 阶段得到 pcplus4D，pcplus4D 和指令的立即数偏转位相加得到跳转指令的地址，跳转指令
    的地址和 pcplus4F 根据跳转信号选择出下一条指令 pcbranchD，然后根据跳转的三个信号
    （jumpD | jrD | jalD）和分支地址选出下一条 pc，下一条 pc 和异常处理地址根据冒险控制信号
    选出真正的下一条 pc（pcfinal），将最后得到的下一条 pc 传入 pc 寄存器中（pc）中。在 pc 处
    理阶段一共用到了三个二选一多选器，先判断跳转、再判断分支跳转、最后判断异常。在 IF 阶段需要
    判断出 pc 的取指异常，通过 pc 后两位是否为 2‘b00 判断。将冒险模块的暂停和刷新指令连接到 D 触
    发器上，是否在需要的时候进行刷新和暂停。
    \item ID 译码阶段。主要得到控制器中得到的控制信号，读取寄存器堆中的数据，对有立
    即数的指令进行操作。控制信号是由 controller 从 datapath 外部传入，在控制器中根
    据指令的结构分别译码得出寄存器写使能 regwriteW、内存写寄存器信号memtoregW、
    分支信号 branchD、运算器控制信号alucontrolE（8 位）、
    第二个运算操作数控制信号 alusrcE、寄存器写地址信号 regdstE、立即数跳转信号 jumpD、
    无条件寄存器跳转信号 jrD、无条件立即数跳转写寄存器信号 jalD、分支写寄存器信号 balD、
    然后通过指令编码得到 rt、rd、rs 寄存器号。从寄存器堆中读出 rd1、rd2 寄存器的值，
    然后根据冒险模块的前推信号处理相等跳转的数据，之后判断相等。然后将立即数位通过位扩展
    得到 32 位的操作数，立即数的扩展分为有符号扩展和无符号扩展，根据输入u进行判断，
    得到的结果的一方面用于计算分支的地址另一方面给可能传入 alu 进行计算。rd1 和 rd2 并不是直接
    的 alu 的输入数据，将 rd1、之前指令的 alu 运算结果、写回结果通过冒险控制信号
    forwardAE 进行三选一得到第一个 alu 操作数。第二个操作数是由 rd2、扩展立即数、
    之前指令运算结果、之前指令写回结果通过二选一和三选一多选器根据第二个运算
    操作数控制信号和冒险模块的数据前推信号 forwardBE 选出 alu 的第二个操作数。
    对于寄存器堆的的写地址，根据写寄存器地址信号选到写目标寄存器是 rt 还是 rd，
    再用判断是否在分支跳转的时候要将虚拟地址写入对应 rd 寄存器（若没有 31 号寄
    存器），得到写寄存器堆的地址。写寄存器的值来自于最后 WB 阶段的结果。因为把
    分支指令的判断提前到 ID 阶段，在此阶段根据冒险控制模块的前推信号
    forwardAD、forwardBD 得到相等判断的跳转数据。在译码阶段根据指令编码得到移
    位偏移 saD 和偏移量 sel 前者用来在移位指令中运算，后者用来在存取指令中
    选择字节数。同时在 ID 阶段要处理将相关的控制信号流入 EXE 阶段。通过带使能、带复位、带清空
    的 D 触发器将 pc+8、寄存器读出来的 rd1 和 rd2、指令信号、立即数扩展数据、sa 移位数据、
    指令偏移量信号传入下一阶段。
    \item EXE 执行阶段，主要是通过 alu 运算单元对正确的运算数据进行运算。rd1 和 rd2 并
    不是直接的 alu 的输入数据，将 rd1、之前指令的 alu 运算结果、写回结果通过冒险控
    制信号 forwardAE 进行三选一得到第一个 alu 操作数。第二个操作数是由 rd2、扩展
    立即数、之前指令运算结果、之前指令写回结果通过二选一和三选一多选器根据第
    二个运算操作数控制信号和冒险模块的数据前推信号 forwardBE 选出 alu 的第二个
    操作数。Alu 和除法器是单独分开的，但是在同一周期开始处理，除法器接受 alu 处
    理后的除数和被除数，除法需要 36 个周期在进行除法的时候会直接暂停流水线，直
    到除法器计算完成才继续流水线，根据 stall\_div 信号进行控制。乘除法得到的结果
    会存在 hilo 寄存器（64 位）中。根据 alu 计算结果可以判断溢出异常和读写存储器
    异常，前者是同号运算时结果异号导致，而后者是由于在读取半字或一个字时地址
    结果尾端并没有正常对齐。数据的通过带有使能、带有复位、带有清空的 D 触发器将执行阶段结果、写内存的
    数据、写寄存器信号、数据偏移量传入 MEM 阶段
    \item MEM 访存阶段，存储器放在 mips 之外，将地址和数据还有使能信号输入
    data\_sram，对于每一个访存指令都得到一个完整一个字的数据。再通过 selectdata
    进行数据选择。通过带使能、带复位、带清空的 D 触发器将 alu 控制信号、读取到的
    数据、写寄存器信号传入 WB 阶段。
    \item WB 写回阶段，写回阶段通过内存写寄存器控制信号二选一内存数据和运算数据，
    将结果作为最终输出，之后将数据流到 ID 阶段的寄存器堆中，有数据前推的根据对
    应阶段的冒险控制信号对结果进行取舍。
\end{itemize}

\subsection{controller模块设计}
\begin{itemize}
    \item controller 模块的结构示意图如下：
    \item 模块输入输出如下：
    \item Controller 模块主要是根据 32 位指令来生成数据通路不同阶段使用的控制信号。其
    中分为了 main\_decoder 模块和 aludec 模块，分别将运算的控制信号单独于其他的
    控制信号。主要的思想就是根据指令的不同位数所待变的不同含义，对相应的信号
    一一赋值。主要包含有 8 位的 alucontrol 信号、写寄存器号控制信号 regdst、寄存器
    堆写使能 regwrite、alu 第二个操作数控制信号 alusrc、内存写使能信号 memwrite、内
    存到寄存器控制信号 memtoreg、分支信号 branch、无条件跳转信号 jump、无条件跳
    转写寄存器信号 jal、寄存器跳转信号 jr、分支写寄存器信号 bal、访存使能信号memen、符号扩展信号u。控制信号是在译
    码阶段生成的，控制信号的管辖范围实在 ID、EXE、MEM、WB 阶段。
    \item ID 译码阶段：在 ID 阶段 controller 接收到指令编码，通过调用 main\_decoder 模块和
    aludec 模块，对指令编码的 op 字段和 funct 字段进行解码。译码的主要过程是先对op 字段进行选择，
    再对 funct 字段进行选择，对应到不同的指令。在 ID 阶段需要用到的信号有：分支信号 branch、
    无条件跳转信号 jump、无条件跳转写寄存器信号 jal、寄存器跳转信号 jr、分支写寄存器信号 bal。
    所有的控制信号都在 ID 阶段输出，在数据通路中进行流水
    \item EXE 执行阶段：在本次设计中，将流水全部放在了数据通路中。在 ID 之后的阶段未
    有流水。在此阶段用到的信号有：8 位的 alucontrol 信号、写寄存器号控制信号regdst、alu 第二个操作数控制信号 alusrc
    \item MEM 访存阶段：在本阶段用到的信号有：寄存器堆写使能 regwrite、内存写使能信号 memwrite 信号
    \item WB 写回阶段：在本阶段使用的信号有：内存到寄存器控制信号 memtoreg。
\end{itemize}

\subsection{main\_decoder模块设计}
\begin{itemize}
    \item 模块输入输出如下：
    \item main\_decoder 模块是 controller 模块下的子模块，通过 op 和 funct 字段进行译码得
    到对应的译码。通过 defines.vh 里的宏定义堆指令进行一一匹配。
    \item 在 main\_decoder 模块里先对 op 字段进行选择，可以先匹配出普通的 R 型指令例如
    与、或、加减等在本模块里的控制信号输出头相同，在 R 型指令中，针对一些特殊的
    指令，比如说数据移动指令、立即数运算指令、分支指令做出不同的译码。
    之后再针对不同的 op 同上进行解码即可，不存在指令集的指令默认译码全零，且输
    出未知指令控制信号 invalid。
\end{itemize}

\subsection{aludec模块设计}
\begin{itemize}
    \item 模块输入输出如下：
    \item aludecode 也同样是用 op 字段和 funct 字段对指令进行译码，最后得到对应的 alu 运
    算控制信号。运算控制信号用 defines.vh 里的宏定义进行标识，是对每一条指令的
    唯一标识，本身不具有特殊含义，在 alu 里根据唯一标识的 alu 控制信号进行相关的
    运算。
    \item 在处理一般的指令时，直接对 alucontrol 赋值 defines.vh 里的相应操作即可。主要分
    为普通 r 型指令、一般非 r 型指令（op 唯一对应一条指令）、特殊分支指令（op==2’
    b000001）、异常处理指令（op==2’b010000）。若是未知指令则默认的 alucontrol 恒为
    全 0。标识不做任何操作。
\end{itemize}